package com.ysd.conf;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.ysd.lis.entity.SysUser;
import com.ysd.util.RedisUserManager;
import com.ysd.util.ToolsUtils;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SubSelect;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.sql.Connection;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author
 * @description 当表无该字段查询条件时增加默认查询条件
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
@Slf4j
@Component
public class SqlInterceptor implements Interceptor {


    private static Map NoOrgIdTableNames =
            MapUtil.builder()
                    .put("sys_organization", "1")
                    .put("user_tab_comments", "2")
                    .put("user_col_comments", "3")
                    .put("dual", "4")
                    .put("limsiqcmaterialbatches", "5")
                    .put("LimsIQCMaterialBatchInsAnss", "6")
                    .put("qrtz_blob_triggers", "7")
                    .put("qrtz_calendars", "8")
                    .put("qrtz_cron_triggers", "9")
                    .put("qrtz_fired_triggers", "10")
                    .put("qrtz_job_details", "11")
                    .put("qrtz_locks", "12")
                    .put("qrtz_paused_trigger_grps", "13")
                    .put("qrtz_scheduler_state", "14")
                    .put("qrtz_simple_triggers", "15")
                    .put("qrtz_simprop_triggers", "16")
                    .put("qrtz_triggers", "7")
                    .put("tables", "17")
                    .put("t_case_table",  "18")
                    .put("t_case_testresult_table", "19")
                    //.put("selecttemp", "18")
                    .map();


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
   /*     ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        Boolean isQuery = true;
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            String requestURI = request.getRequestURI(); // 获取请求路径
            if(requestURI.contains("organizeLis")){
                log.info("请求路径: {}", requestURI);
                isQuery=false;
            }
        }*/
        RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
        //获取StatementHandler构造器
        StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(handler, "delegate");
        // 通过反射获取delegate父类BaseStatementHandler的mappedStatement属性
        MappedStatement mappedStatement = (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement");
        SqlCommandType commandType = mappedStatement.getSqlCommandType();
        if (SqlCommandType.SELECT.equals(commandType)) {
            String sqlId = mappedStatement.getId();
            BoundSql boundSql = delegate.getBoundSql();
            String sql = boundSql.getSql();
            String leftSql = addOrgIdLeftCondition(sql);
            String newSql = addOrgIdInnerCondition(leftSql);
            try {
                Statement statement = CCJSqlParserUtil.parse(newSql);
                Select select = (Select) statement;
                PlainSelect selectBody = (PlainSelect) select.getSelectBody();
                addWhere(selectBody);
                ReflectUtil.setFieldValue(boundSql, "sql", statement.toString());
            } catch (Exception e) {
                ReflectUtil.setFieldValue(boundSql, "sql", newSql.toString());
            }
        }
        return invocation.proceed();

    }

    /**
     * inner join 添加org_id
     *
     * @param sql
     * @return
     */
    private String addOrgIdLeftCondition(String sql) {


        try {
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (Objects.isNull(requestAttributes)) {
                return sql;
            }
            HttpServletRequest request = requestAttributes.getRequest();
            String authorization = request.getHeader("Authorization");
            if(ToolsUtils.isNotEmpty(authorization)){
                String token = authorization.replace("Bearer ", "");
                String orgId = RedisUserManager.getStoreOrg("currentOrg" + token);
                String value = RedisUserManager.getStoreOrg("skip_filter_orgid");
                if (StringUtils.isNotBlank(value)) {
                    orgId = value;
                }
                Pattern joinPattern = Pattern.compile("(LEFT\\s+JOIN\\s+\\w+\\s+\\w+\\s+ON.+?)", Pattern.CASE_INSENSITIVE);
                Matcher joinMatcher = joinPattern.matcher(sql);

                StringBuffer newSql = new StringBuffer();

                while (joinMatcher.find()) {
                    // 提取表名和别名
                    String joinClause = joinMatcher.group();
                    String[] parts = joinClause.split("\\s+");
                    String table = parts[2]; // 假设别名是第四个部分
                    if (StringUtils.isNotBlank((String) NoOrgIdTableNames.get(table.toLowerCase()))) {
                        break;
                    }
                    String alias = parts[3]; // 假设别名是第四个部分
                    joinMatcher.appendReplacement(newSql, "$1" + alias + ".org_id = " + "'" + orgId + "' AND ");
                }

                joinMatcher.appendTail(newSql);
                return newSql.toString();
            }
        } catch (Exception e) {
            log.info("获取缓存失败");
        }


        return sql;
    }

    /**
     * inner join 添加org_id
     *
     * @param sql
     * @return
     */
    private String addOrgIdInnerCondition(String sql) {


        try {
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (Objects.isNull(requestAttributes)) {
                return sql;
            }
            HttpServletRequest request = requestAttributes.getRequest();
            String authorization = request.getHeader("Authorization");
            if(ToolsUtils.isNotEmpty(authorization)){
                String token = authorization.replace("Bearer ", "");
                String orgId = RedisUserManager.getStoreOrg("currentOrg" + token);
                String value = RedisUserManager.getStoreOrg("skip_filter_orgid");
                if (StringUtils.isNotBlank(value)) {
                    orgId = value;
                }
                Pattern joinPattern = Pattern.compile("(INNER\\s+JOIN\\s+\\w+\\s+\\w+\\s+ON.+?)", Pattern.CASE_INSENSITIVE);
                Matcher joinMatcher = joinPattern.matcher(sql);

                StringBuffer newSql = new StringBuffer();

                while (joinMatcher.find()) {
                    // 提取表名和别名
                    String joinClause = joinMatcher.group();
                    String[] parts = joinClause.split("\\s+");
                    String table = parts[2]; // 假设别名是第四个部分
                    if (StringUtils.isNotBlank((String) NoOrgIdTableNames.get(table.toLowerCase()))) {
                        break;
                    }
                    String alias = parts[3]; // 假设别名是第四个部分
                    joinMatcher.appendReplacement(newSql, "$1" + alias + ".org_id = " + "'" + orgId + "' AND ");
                }

                joinMatcher.appendTail(newSql);
                return newSql.toString();
            }
        } catch (Exception e) {
            log.info("获取缓存失败");
        }


        return sql;
    }

    //增加条件
    private void addWhere(PlainSelect selectBody) {
        try {
            Table fromItem = (Table) selectBody.getFromItem();
            String name = fromItem.getName();
            Alias alias = fromItem.getAlias();
            SysUser user = null;
            try {
                user = RedisUserManager.getUser();
            } catch (Exception e) {
            }
            if (user != null ) {
                //不需要添加组织机构的表有
                if (StringUtils.isBlank((String) NoOrgIdTableNames.get(name.toLowerCase()))) {
                    String stringExpression = "";
                    try {
                        EqualsTo where = (EqualsTo) selectBody.getWhere();
                        stringExpression = where.getStringExpression();
                    } catch (Exception e) {
                        if (selectBody.getWhere() != null) {
                            stringExpression = selectBody.getWhere().toString();
                        }
                    }
                    //如果字段搜索条件为空则搜索字段为空或指定数据
                    StringBuilder sqlFilter = new StringBuilder(128);


                    if (stringExpression.indexOf("org_id") == -1) {
                        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                        HttpServletRequest request = requestAttributes.getRequest();
                        try {
                            String authorization = request.getHeader("Authorization");
                            if(ToolsUtils.isNotEmpty(authorization)){
                                String token = authorization.replace("Bearer ", "");
                                String orgId = RedisUserManager.getStoreOrg("currentOrg" + token);
                                String value = RedisUserManager.getStoreOrg("skip_filter_orgid");
                                if (StringUtils.isBlank(value)) {
                                    sqlFilter.append(" (" + (alias == null ? "" : (alias.getName() + ".")) + "ORG_ID='" + orgId + "') ");
                                }
                            }
                        } catch (Exception e) {
                            sqlFilter.append(" 1=1 ");
                            log.info("获取缓存失败");
                        }
                        buildWhereClause(selectBody, sqlFilter.toString());
                    }
                }
            }
        } catch (Exception e) {
            //多表查询时由于不是最后一层，获取不到Table，继续获取子表
            SubSelect ss = (SubSelect) selectBody.getFromItem();
            log.error("子sql语句为：" + ss.getSelectBody());
            PlainSelect subSelect = (PlainSelect) ss.getSelectBody();
            addWhere(subSelect);
        }
    }


    private void buildWhereClause(PlainSelect select, String dataFilter) throws JSQLParserException {
        if (select.getWhere() == null) {
            select.setWhere(CCJSqlParserUtil.parseCondExpression(dataFilter));
        } else {
            AndExpression and = new AndExpression(
                    CCJSqlParserUtil.parseCondExpression(dataFilter), select.getWhere());
            select.setWhere(and);
        }
    }
}


